package com.zphhhhh.speech;

import android.content.Context;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;

import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.facebook.react.uimanager.IllegalViewOperationException;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechError;
import com.iflytek.cloud.SpeechSynthesizer;
import com.iflytek.cloud.SpeechUtility;
import com.iflytek.cloud.SynthesizerListener;

/**
 * Created by cn_pa on 2016/11/25.
 * 提供讯飞语音合成 React Native 接口
 */

public class SpeechSynthesizerModule extends ReactContextBaseJavaModule {

    private static final String TAG = "ReactNative-speech";

    private Context context;

    private SpeechSynthesizer mTts;
    private SynthesizerListener mTtsListener;

    private static long startTime;
    private static long endTime;
    private String content;
    private String filename;

    // bugFix: 修复文章内容过长时，语音合成失败的问题 - tiangui @ 20191028
    private static final int MODE_WHOLE = 1; // 完整模式
    private static final int MODE_SPLIT = 2; // 拆分模式

    private int currentMode;
    private int partIndex;
    private String[] partArr;

    public SpeechSynthesizerModule(ReactApplicationContext reactContext) {
        super(reactContext);
        this.context = reactContext;
    }

    @Override
    public String getName() {
        return "SpeechSynthesizerModule";
    }

    @ReactMethod
    public void init(String AppId) {
        if (mTts != null) {
            return;
        }

        SpeechUtility.createUtility(this.context, SpeechConstant.APPID + "=" + AppId);

        mTts = SpeechSynthesizer.createSynthesizer(this.context, null);
        mTtsListener = new SynthesizerListener() {
            @Override
            public void onBufferProgress(int percent, int beginPos, int endPos, String s) {
                // 合成进度
                if (percent == 100) {
                    WritableMap params = Arguments.createMap();
                    params.putString("content", content);
                    params.putString("filename", filename);
                    _emitEvent("onBufferCompleted", params);
                }
            }

            @Override
            public void onSpeakBegin() {
                _emitEvent("onSpeakBegin", null);
            }

            @Override
            public void onSpeakPaused() {
                _emitEvent("onSpeakPaused", null);
            }

            @Override
            public void onSpeakResumed() {
                _emitEvent("onSpeakResumed", null);
            }

            @Override
            public void onSpeakProgress(int percent, int beginPos, int endPos) {
                // 播放进度
            }

            @Override
            public void onCompleted(SpeechError speechError) {
                // 播放完成
                // 错误码查询: https://www.xfyun.cn/document/error-code
                Log.d(TAG, "onCompleted(): " + speechError);

                int errorCode = (speechError != null) ? speechError.getErrorCode() : 0;

                if (errorCode == 10117 && currentMode == MODE_WHOLE) {
                    currentMode = MODE_SPLIT;
                    partArr = SpeechUtil.split(content);
                    partIndex = 0;
                    mTts.startSpeaking(partArr[partIndex], mTtsListener);
                    return;
                }

                if (errorCode == 0 && currentMode == MODE_SPLIT) {
                    partIndex++;
                    if (partIndex <= partArr.length - 1) {
                        mTts.startSpeaking(partArr[partIndex], mTtsListener);
                    } else {
                        onTtsCompleted();
                    }
                    return;
                }

                onTtsCompleted();
            }

            @Override
            public void onEvent(int i, int i1, int i2, Bundle bundle) {

            }
        };
        setTtsParam();
    }

    @ReactMethod
    public void start(String content) {
        if (mTts == null) return;
        startTime = System.currentTimeMillis();

        if (mTts.isSpeaking()) {
            mTts.stopSpeaking();
        }

        this.content = content;
        currentMode = MODE_WHOLE; // 默认完整模式
        mTts.startSpeaking(content, mTtsListener);
    }

    @ReactMethod
    public void stop() {
        if (mTts == null) return;
        if (mTts.isSpeaking()) {
            mTts.stopSpeaking();
        }
        currentMode = 0;
        partIndex = -1;
        partArr = null;
    }

    @ReactMethod
    public void pause() {
        if (mTts == null) return;
        if (mTts.isSpeaking()) {
            mTts.pauseSpeaking();
        }
    }

    @ReactMethod
    public void resume() {
        if (mTts == null) return;
        if (mTts.isSpeaking()) {
            mTts.resumeSpeaking();
        }
    }

    @ReactMethod
    public void isSpeaking(Promise promise) {
        try {
            promise.resolve(mTts.isSpeaking());
        } catch (IllegalViewOperationException e) {
            promise.reject("Error : isSpeaking()", e);
        }
    }

    @ReactMethod
    public void synthesizeToFile(String content, String filename, Promise promise) {
        if (mTts.isSpeaking()) {
            mTts.stopSpeaking();
        }

        this.content = content;
        this.filename = filename;

        setTtsParam();
        int result = mTts.synthesizeToUri(content, Environment.getExternalStorageDirectory() + filename, mTtsListener);
        try {
            promise.resolve(result);
        } catch (IllegalViewOperationException e) {
            promise.reject("Error: synthesizeToFile()", e);
        }
    }

    @ReactMethod
    public void setParameter(String parameter, String value) {
        if (parameter.equals(SpeechConstant.TTS_AUDIO_PATH)) {
            value = Environment.getExternalStorageDirectory() + value;
        }
        mTts.setParameter(parameter, value);
    }

    private void setTtsParam() {
        // 清空参数
        mTts.setParameter(SpeechConstant.PARAMS, null);

        mTts.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD);
        // 设置在线合成发音人
        mTts.setParameter(SpeechConstant.VOICE_NAME, "xiaoyan");
        //设置合成语速
        mTts.setParameter(SpeechConstant.SPEED, "50");
        //设置合成音调
        mTts.setParameter(SpeechConstant.PITCH, "50");
        //设置合成音量
        mTts.setParameter(SpeechConstant.VOLUME, "50");

        //设置播放器音频流类型
        mTts.setParameter(SpeechConstant.STREAM_TYPE, "3");
        // 设置播放合成音频打断音乐播放，默认为true
        mTts.setParameter(SpeechConstant.KEY_REQUEST_FOCUS, "true");

        // 设置音频保存路径，保存音频格式支持pcm、wav，设置路径为sd卡请注意WRITE_EXTERNAL_STORAGE权限
        // 注：AUDIO_FORMAT参数语记需要更新版本才能生效
        mTts.setParameter(SpeechConstant.AUDIO_FORMAT, "wav");
        mTts.setParameter(SpeechConstant.TTS_AUDIO_PATH, Environment.getExternalStorageDirectory() + "/App/Synthesizer");
    }

    private void onTtsCompleted() {
        endTime = System.currentTimeMillis();
        int duration = (int) (endTime - startTime);

        WritableMap params = Arguments.createMap();
        params.putInt("duration", duration);

        _emitEvent("onCompleted", null);
    }

    private void _emitEvent(String eventName, WritableMap params) {
        Log.d(TAG, "_emitEvent(): " + eventName);

        if (params == null) {
            params = new WritableNativeMap();
        }
        params.putString("msg", eventName);

        getReactApplicationContext()
                .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit("SpeechSynthesizerEvent", params);
    }

}
